#include <linux/types.h>
#include <net/sock.h>
#include <net/netlink.h>
#include <linux/ip.h>
#include <linux/module.h>
#include <linux/netlink.h>
#include <net/genetlink.h>

enum {
	DEMO_CMD_UNSPEC = 0,	/* Reserved */
	DEMO_CMD_ECHO,			/* user->kernel request/get-response */
	DEMO_CMD_REPLY,			/* kernel->user event */
	__DEMO_CMD_MAX,
};
#define DEMO_CMD_MAX (__DEMO_CMD_MAX - 1)

enum {
	DEMO_CMD_ATTR_UNSPEC = 0,
	DEMO_CMD_ATTR_MESG,		/* demo message  */
	DEMO_CMD_ATTR_DATA,		/* demo data */
	__DEMO_CMD_ATTR_MAX,
};
#define DEMO_CMD_ATTR_MAX (__DEMO_CMD_ATTR_MAX - 1)


#define DEMO_GENL_FAMILY_NAME "DEMO"

static const struct nla_policy demo_cmd_policy[DEMO_CMD_ATTR_MAX+1] = {
	[DEMO_CMD_ATTR_MESG]	= { .type = NLA_STRING },
	[DEMO_CMD_ATTR_DATA]	= { .type = NLA_S32 },	
};

static int demo_echo_cmd(struct sk_buff *skb, struct genl_info *info);

static struct genl_ops demo_ops[] = {
    {
        .cmd = DEMO_CMD_ECHO,
        .doit = demo_echo_cmd,
    },
};

static struct genl_family demo_family = {
    .module = THIS_MODULE,
    .ops = demo_ops,
    .n_ops = ARRAY_SIZE(demo_ops),
    .name = DEMO_GENL_FAMILY_NAME,
    .version = 1,
    .maxattr = DEMO_CMD_ATTR_MAX,
    .policy = demo_cmd_policy,
};

static int demo_echo_cmd(struct sk_buff *skb, struct genl_info *info)
{
    printk("hello: demo_echo_cmd start \n");
    return 0;
}

static int __init netlink_test_init(void)
{
    int ret;

    printk("hello: hello netlink");

    ret = genl_register_family(&demo_family);

    if (ret < 0) {
        printk("hello module register generic netlink failed!\n");
    } else {
        printk("hello module register generic netlink success, demo_family.id is [%d] \n", demo_family.id);
    }

    return 0;
}

static void __exit netlink_test_exit(void)
{
    genl_unregister_family(&demo_family);
    printk("hello module netlink exit! \n");
}

module_init(netlink_test_init);
module_exit(netlink_test_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("netlink test");